// scoped_allocator standard header
#pragma once
#ifndef _SCOPED_ALLOCATOR_
#define _SCOPED_ALLOCATOR_
#ifndef RC_INVOKED
#include <tuple>
#include <xmemory0>

 #pragma pack(push,_CRT_PACKING)
 #pragma warning(push,_STL_WARNING_LEVEL)
 #pragma warning(disable: _STL_DISABLED_WARNINGS)
 #pragma push_macro("new")
 #undef new

 #pragma warning(disable: 4494)	// Ignoring __declspec(allocator) because the
								// function return type is not a pointer or reference

_STD_BEGIN
		// FUNCTION TEMPLATE _Scoped_outermost
struct _Scoped_outermost_helper_tag
	{	// TRANSITION, C1XX
	};

template<class _Alloc,
	class = void>
	struct _Scoped_outermost_helper
	{	// gets the outermost allocator
	static decltype(auto) _Fn(_Alloc& _Al)
		{	// gets the outermost allocator
		return (_Al);
		}
	};

template<class _Alloc>
	struct _Scoped_outermost_helper<_Alloc, void_t<
			_Scoped_outermost_helper_tag,	// TRANSITION, C1XX
			decltype(_STD declval<_Alloc&>().outer_allocator())>>
	{	// gets the outermost allocator
	typedef decltype(_STD declval<_Alloc&>().outer_allocator()) _Outer_alloc;

	static decltype(auto) _Fn(_Alloc& _Al)
		{	// gets the outermost allocator
		return (_Scoped_outermost_helper<_Outer_alloc>::_Fn(_Al.outer_allocator()));
		}
	};

template<class _Alloc> inline
	decltype(auto) _Scoped_outermost(_Alloc& _Al)
	{	// gets the outermost allocator
	return (_Scoped_outermost_helper<_Alloc>::_Fn(_Al));
	}


		// ALIAS TEMPLATE _Scoped_outermost_t
template<class _Alloc>
	using _Scoped_outermost_t
		= remove_reference_t<decltype(_Scoped_outermost(_STD declval<_Alloc&>()))>;


		// ALIAS TEMPLATE _Scoped_outermost_traits
template<class _Alloc>
	using _Scoped_outermost_traits
		= allocator_traits<_Scoped_outermost_t<_Alloc>>;


		// TEMPLATE FUNCTION _Scoped_construct_tuple
template<class _Ty,
	class _Alloc,
	class... _Atypes> inline
	tuple<_Atypes...>&&
		_Scoped_construct_tuple(_Alloc&, false_type, _Any_tag,
			tuple<_Atypes...>&& _Val)
	{	// construct tuple from tuple argument, no allocator
	static_assert(is_constructible<_Ty, _Atypes...>::value,
		"N4582 20.16.4 [allocator.adaptor.members]/11 requires "
		"is_constructible<T, Args...> "
		"when uses_allocator<T, inner_allocator_type> is false");
	return (_STD move(_Val));
	}

template<class _Ty,
	class _Alloc,
	class... _Atypes> inline
	tuple<allocator_arg_t, _Alloc&, _Atypes...>
		_Scoped_construct_tuple(_Alloc& _Alty, true_type, true_type,
			tuple<_Atypes...>&& _Val)
	{	// construct tuple from tuple argument, leading allocator
	return (_STD tuple_cat(
		tuple<allocator_arg_t, _Alloc&>(allocator_arg, _Alty),
		_STD move(_Val)));
	}

template<class _Ty,
	class _Alloc,
	class... _Atypes> inline
	tuple<_Atypes..., _Alloc&>
		_Scoped_construct_tuple(_Alloc& _Alty, true_type, false_type,
			tuple<_Atypes...>&& _Val)
	{	// construct tuple from tuple argument, trailing allocator
	static_assert(is_constructible<_Ty, _Atypes..., _Alloc&>::value,
		"N4582 20.16.4 [allocator.adaptor.members]/11 requires "
		"is_constructible<T, allocator_arg_t, inner_allocator_type&, Args...> or "
		"is_constructible<T, Args..., inner_allocator_type&> "
		"when uses_allocator<T, inner_allocator_type> is true");
	return (_STD tuple_cat(_STD move(_Val),
		tuple<_Alloc&>(_Alty)));
	}


		// TEMPLATE CLASS _Scoped_base
template<class _Outer,
	class... _Inner>
	class scoped_allocator_adaptor;

template<class _Outer,
	class... _Inner>
	struct _Scoped_base;

template<class _Outer,
	class _Inner0,
	class... _Inner>
	struct _Scoped_base<_Outer, _Inner0, _Inner...>
		: public _Outer
	{	// nest of allocators, arbitrary depth
	typedef scoped_allocator_adaptor<_Outer, _Inner0, _Inner...>
		_Myadaptor;
	typedef scoped_allocator_adaptor<_Inner0, _Inner...>
		inner_allocator_type;

	inner_allocator_type _Inner_obj;

	inner_allocator_type& _Get_inner_object(
		_Myadaptor&)
		{	// return _Inner_obj as inner_object
		return (_Inner_obj);
		}

	const inner_allocator_type& _Get_inner_object(
		const _Myadaptor&) const
		{	// return _Inner_obj as inner_object
		return (_Inner_obj);
		}

	_Scoped_base()
		: _Outer(),
		_Inner_obj()
		{	// value-initialize Outer and Inner
		}

	template<class _Other1,
		class... _Other2>
		_Scoped_base(_Other1&& _Outer_arg,
			_Other2&&... _Inner_args)
		: _Outer(_STD forward<_Other1>(_Outer_arg)),
		_Inner_obj(_STD forward<_Other2>(_Inner_args)...)
		{	// construct from (outer, inners...)
			// also handles rebinding
		}

	_Scoped_base(const _Scoped_base&) = default;
	_Scoped_base(_Scoped_base&&) = default;
	_Scoped_base& operator=(const _Scoped_base&) = default;
	_Scoped_base& operator=(_Scoped_base&&) = default;

	_Myadaptor select_on_container_copy_construction() const
		{	// make new adaptor
		return (_Myadaptor(allocator_traits<_Outer>::select_on_container_copy_construction(
			static_cast<const _Outer&>(*this)),
			_Inner_obj.select_on_container_copy_construction()));
		}
	};

template<class _Outer>
	struct _Scoped_base<_Outer>
		: public _Outer
	{	// nest of allocators, one deep
	typedef scoped_allocator_adaptor<_Outer> _Myadaptor;
	typedef scoped_allocator_adaptor<_Outer> inner_allocator_type;

	inner_allocator_type& _Get_inner_object(
		_Myadaptor& _Self)
		{	// return self as inner_object
		return (_Self);
		}

	const inner_allocator_type& _Get_inner_object(
		const _Myadaptor& _Self) const
		{	// return self as inner_object
		return (_Self);
		}

	_Scoped_base()
		: _Outer()
		{	// value-initialize
		}

	template<class _Other1>
		_Scoped_base(_Other1&& _Outer_arg)
		: _Outer(_STD forward<_Other1>(_Outer_arg))
		{	// construct from (outer, inner)
			// also handles rebinding
		}

	_Scoped_base(const _Scoped_base&) = default;
	_Scoped_base(_Scoped_base&&) = default;
	_Scoped_base& operator=(const _Scoped_base&) = default;
	_Scoped_base& operator=(_Scoped_base&&) = default;

	_Myadaptor select_on_container_copy_construction() const
		{	// make new adaptor
		return (_Myadaptor(allocator_traits<_Outer>::select_on_container_copy_construction(
			static_cast<const _Outer&>(*this))));
		}
	};

		// TEMPLATE CLASS scoped_allocator_adaptor
template<class _Outer,
	class... _Inner>
	class scoped_allocator_adaptor
		: public _Scoped_base<_Outer, _Inner...>
	{	// nest of allocators
	typedef _Scoped_base<_Outer, _Inner...> _Mybase;
	typedef allocator_traits<_Outer> _Outer_traits;

public:
	typedef _Outer outer_allocator_type;
	typedef typename _Mybase::inner_allocator_type inner_allocator_type;

	typedef typename _Outer_traits::value_type value_type;
	typedef typename _Outer_traits::pointer pointer;
	typedef typename _Outer_traits::const_pointer const_pointer;
	typedef typename _Outer_traits::void_pointer void_pointer;
	typedef typename _Outer_traits::const_void_pointer const_void_pointer;

	typedef typename _Outer_traits::size_type size_type;
	typedef typename _Outer_traits::difference_type difference_type;

	template<class _Other>
		struct rebind
		{	// converts X<value_type> to X<_Other>
		typedef typename _Get_rebind_type<_Outer, _Other>::type _Other_alloc;
		typedef scoped_allocator_adaptor<_Other_alloc, _Inner...> other;
		};

	typedef bool_constant<disjunction<
		typename allocator_traits<_Outer>::propagate_on_container_copy_assignment,
		typename allocator_traits<_Inner>::propagate_on_container_copy_assignment...>::value>
			propagate_on_container_copy_assignment;

	typedef bool_constant<disjunction<
		typename allocator_traits<_Outer>::propagate_on_container_move_assignment,
		typename allocator_traits<_Inner>::propagate_on_container_move_assignment...>::value>
			propagate_on_container_move_assignment;

	typedef bool_constant<disjunction<
		typename allocator_traits<_Outer>::propagate_on_container_swap,
		typename allocator_traits<_Inner>::propagate_on_container_swap...>::value>
			propagate_on_container_swap;

	typedef bool_constant<conjunction<
		typename allocator_traits<_Outer>::is_always_equal,
		typename allocator_traits<_Inner>::is_always_equal...>::value>
			is_always_equal;

	scoped_allocator_adaptor() = default; // value-init handled in _Scoped_base

	template<class _Other>
		scoped_allocator_adaptor(_Other&& _Other_arg,
			const _Inner&... _Inner_args) _NOEXCEPT
		: _Mybase(_STD forward<_Other>(_Other_arg),
			_Inner_args...)
		{	// construct from (_Other, _Inner...)
			// also handles rebinding construction when sizeof...(_Inner) == 0
		}

	scoped_allocator_adaptor(const scoped_allocator_adaptor& _Right) _NOEXCEPT
		: _Mybase(_Right)
		{	// construct from _Right
		}

	scoped_allocator_adaptor(scoped_allocator_adaptor&& _Right) _NOEXCEPT
		: _Mybase(_STD move(_Right))
		{	// construct from _Right
		}

	template<class _Other,
		bool _Enabled = sizeof...(_Inner) != 0,
		class = enable_if_t<_Enabled>>
		scoped_allocator_adaptor(const scoped_allocator_adaptor<_Other,
			_Inner...>& _Right) _NOEXCEPT
		: _Mybase(_Right.outer_allocator(),
			_Right.inner_allocator())
		{	// construct from const adaptor<_Other, _Inner...>&
		}

	template<class _Other,
		bool _Enabled = sizeof...(_Inner) != 0,
		class = enable_if_t<_Enabled>>
		scoped_allocator_adaptor(scoped_allocator_adaptor<_Other,
			_Inner...>&& _Right) _NOEXCEPT
		: _Mybase(_STD move(_Right.outer_allocator()),
			_STD move(_Right.inner_allocator()))
		{	// construct from adaptor<_Other, _Inner...>&&
		}

	scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default;
	scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default;

	inner_allocator_type& inner_allocator() _NOEXCEPT
		{	// get reference to inner allocator
		return (this->_Get_inner_object(*this));
		}

	const inner_allocator_type& inner_allocator() const _NOEXCEPT
		{	// get reference to inner allocator
		return (this->_Get_inner_object(*this));
		}

	outer_allocator_type& outer_allocator() _NOEXCEPT
		{	// get reference to outer allocator
		return (static_cast<_Outer&>(*this));
		}

	const outer_allocator_type& outer_allocator() const _NOEXCEPT
		{	// get reference to outer allocator
		return (static_cast<const _Outer&>(*this));
		}

	_DECLSPEC_ALLOCATOR pointer allocate(_CRT_GUARDOVERFLOW size_type _Count)
		{	// allocate array of _Count elements, ignore hint
		return (_Outer_traits::allocate(outer_allocator(),
			_Count));
		}

	_DECLSPEC_ALLOCATOR pointer allocate(_CRT_GUARDOVERFLOW size_type _Count, const_void_pointer _Hint)
		{	// allocate array of _Count elements, with hint
		return (_Outer_traits::allocate(outer_allocator(),
			_Count, _Hint));
		}

	void deallocate(pointer _Ptr, size_type _Count)
		{	// deallocate object at _Ptr, with size
		return (_Outer_traits::deallocate(outer_allocator(),
			_Ptr, _Count));
		}

	size_type max_size() const
		{	// estimate maximum array size
		return (_Outer_traits::max_size(outer_allocator()));
		}

	template<class _Ty,
		class... _Types>
		void _Construct1(false_type, _Any_tag, _Ty *_Ptr, _Types&&... _Args)
		{	// construct with uses_allocator<T, inner_allocator_type> == false
		static_assert(is_constructible<_Ty, _Types...>::value,
			"N4582 20.16.4 [allocator.adaptor.members]/9 requires "
			"is_constructible<T, Args...> "
			"when uses_allocator<T, inner_allocator_type> is false");
		_Scoped_outermost_traits<scoped_allocator_adaptor>::construct(
			_Scoped_outermost(*this),
			_Ptr,
			_STD forward<_Types>(_Args)...);
		}

	template<class _Ty,
		class... _Types>
		void _Construct1(true_type, true_type, _Ty *_Ptr, _Types&&... _Args)
		{	// construct with uses_allocator<_Ty, inner_allocator_type> and
			// is_constructible<_Ty, allocator_arg_t, inner_allocator_type&, _Types...>
		_Scoped_outermost_traits<scoped_allocator_adaptor>::construct(
			_Scoped_outermost(*this),
			_Ptr,
			allocator_arg,
			inner_allocator(),
			_STD forward<_Types>(_Args)...);
		}

	template<class _Ty,
		class... _Types>
		void _Construct1(true_type, false_type, _Ty *_Ptr, _Types&&... _Args)
		{	// construct with uses_allocator<_Ty, inner_allocator_type> and
			// is_constructible<_Ty, _Types..., inner_allocator_type&>
		static_assert(is_constructible<_Ty, _Types..., inner_allocator_type&>::value,
			"N4582 20.16.4 [allocator.adaptor.members]/9 requires "
			"is_constructible<T, allocator_arg_t, inner_allocator_type&, Args...> or "
			"is_constructible<T, Args..., inner_allocator_type&> "
			"when uses_allocator<T, inner_allocator_type> == true");
		_Scoped_outermost_traits<scoped_allocator_adaptor>::construct(
			_Scoped_outermost(*this),
			_Ptr,
			_STD forward<_Types>(_Args)...,
			inner_allocator());
		}

	template<class _Ty,
		class... _Types>
		void construct(_Ty *_Ptr, _Types&&... _Args)
		{	// construct with varying allocator styles
		_Construct1(
			uses_allocator<_Ty, inner_allocator_type>(),
			typename is_constructible<
				_Ty, allocator_arg_t, inner_allocator_type&, _Types...>::type(),
			_Ptr,
			_STD forward<_Types>(_Args)...);
		}

	template<class _Ty1,
		class _Ty2,
		class... _Types1,
		class... _Types2>
		void construct(pair<_Ty1, _Ty2> *_Ptr, piecewise_construct_t,
			tuple<_Types1...> _Val1, tuple<_Types2...> _Val2)
		{	// construct pair from tuples
		_Scoped_outermost_traits<scoped_allocator_adaptor>::construct(
			_Scoped_outermost(*this),
			_Ptr,
			piecewise_construct,
			_Scoped_construct_tuple<_Ty1>(inner_allocator(),
				uses_allocator<_Ty1, inner_allocator_type>(),
				typename is_constructible<
					_Ty1, allocator_arg_t, inner_allocator_type&, _Types1...>::type(),
				_STD move(_Val1)),
			_Scoped_construct_tuple<_Ty2>(inner_allocator(),
				uses_allocator<_Ty2, inner_allocator_type>(),
				typename is_constructible<
					_Ty2, allocator_arg_t, inner_allocator_type&, _Types2...>::type(),
				_STD move(_Val2)));
		}

	template<class _Ty1,
		class _Ty2>
		void construct(pair<_Ty1, _Ty2> *_Ptr)
		{	// construct pair from pointer to other pair
		this->construct(_Ptr, piecewise_construct,
			tuple<>(),
			tuple<>());
		}

	template<class _Ty1,
		class _Ty2,
		class _Uy1,
		class _Uy2>
		void construct(pair<_Ty1, _Ty2> *_Ptr,
			_Uy1&& _Val1, _Uy2&& _Val2)
		{	// construct pair from two movable values
		this->construct(_Ptr, piecewise_construct,
			_STD forward_as_tuple(_STD forward<_Uy1>(_Val1)),
			_STD forward_as_tuple(_STD forward<_Uy2>(_Val2)));
		}

	template<class _Ty1,
		class _Ty2,
		class _Uy1,
		class _Uy2>
		void construct(pair<_Ty1, _Ty2> *_Ptr,
			const pair<_Uy1, _Uy2>& _Other)
		{	// construct pair from copyable pair
		this->construct(_Ptr, piecewise_construct,
			_STD forward_as_tuple(_Other.first),
			_STD forward_as_tuple(_Other.second));
		}

	template<class _Ty1,
		class _Ty2,
		class _Uy1,
		class _Uy2>
		void construct(pair<_Ty1, _Ty2> *_Ptr,
			pair<_Uy1, _Uy2>&& _Other)
		{	// construct pair from movable pair
		this->construct(_Ptr, piecewise_construct,
			_STD forward_as_tuple(_STD forward<_Uy1>(_Other.first)),
			_STD forward_as_tuple(_STD forward<_Uy2>(_Other.second)));
		}

	template<class _Ty>
		void destroy(_Ty *_Ptr)
		{	// destroy object at _Ptr
		_Scoped_outermost_traits<scoped_allocator_adaptor>::destroy(
			_Scoped_outermost(*this), _Ptr);
		}

	// select_on_container_copy_construction comes from _Scoped_base
	};

template<class _Outer1,
	class _Outer2,
	class _Inner1,
	class... _Inner> inline
	bool operator==(
		const scoped_allocator_adaptor<_Outer1, _Inner1, _Inner...>& _Left,
		const scoped_allocator_adaptor<_Outer2, _Inner1, _Inner...>& _Right)
			_NOEXCEPT
		{	// compare scoped_allocator_adaptors for equality
		return (_Left.outer_allocator() == _Right.outer_allocator()
			&& _Left.inner_allocator() == _Right.inner_allocator());
		}

template<class _Outer1,
	class _Outer2> inline
	bool operator==(
		const scoped_allocator_adaptor<_Outer1>& _Left,
		const scoped_allocator_adaptor<_Outer2>& _Right) _NOEXCEPT
		{	// compare scoped_allocator_adaptors for equality
		return (_Left.outer_allocator() == _Right.outer_allocator());
		}

template<class _Outer1,
	class _Outer2,
	class... _Inner> inline
	bool operator!=(
		const scoped_allocator_adaptor<_Outer1, _Inner...>& _Left,
		const scoped_allocator_adaptor<_Outer2, _Inner...>& _Right) _NOEXCEPT
		{	// compare scoped_allocator_adaptors for equality
		return (!(_Left == _Right));
		}

_STD_END
 #pragma pop_macro("new")
 #pragma warning(pop)
 #pragma pack(pop)
#endif /* RC_INVOKED */
#endif /* _SCOPED_ALLOCATOR_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0009 */
